Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / core / model / src / commonMain / kotlin / org / meshtastic / core / model / util / ChannelSetReplacement.kt

Displaying Raw • Download

core/model/src/commonMain/kotlin/org/meshtastic/core/model/util/ChannelSetReplacement.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 6.40 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.model.util

Tff7b72import T7ee787okio.ByteString
Tff7b72import T7ee787org.meshtastic.proto.Channel
Tff7b72import T7ee787org.meshtastic.proto.ChannelSet
Tff7b72import T7ee787org.meshtastic.proto.ChannelSettings
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.core.model.Channel Tff7b72as Te6edf3ModelChannel

T8b949e/** Firmware channel files expose eight slots: one primary plus up to seven secondary channels. */
Tff7b72const Tff7b72val Te6edf3CHANNEL_REPLACEMENT_SLOT_COUNT Tff7b72= T79c0ff8

T8b949e/** A normalized authoritative channel set and the complete radio writes needed to materialize it. */
Tff7b72data Tff7b72class T56d364ChannelReplacementPlanTb4b4b4(Tff7b72val Te6edf3normalizedSettingsTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72>Tb4b4b4, Tff7b72val Te6edf3channelWritesTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelTff7b72>Tb4b4b4)

T8b949e/**
* Produces the canonical authoritative replacement plan used by every full channel-set import path.
*
* Normalization runs before the firmware-slot bound is checked, allowing padded exports to shed blank or duplicate
* secondaries before validation. [requirePrimary] lets profile installation reject an empty decoded set while the
* explicit QR replacement flow retains its existing ability to clear every slot.
*
* @param currentSettings The destination's current settings. Only the size is used when deciding which trailing slots
* must be disabled.
* @param fallbackLoraConfig LoRa config used for semantic identity when this channel set does not carry one.
* @param requirePrimary Whether an empty normalized set must be rejected.
*/
Tff7b72fun Te6edf3ChannelSetTb4b4b4.Td2a8fftoChannelReplacementPlanTb4b4b4(
Te6edf3currentSettingsTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72>Tb4b4b4,
Te6edf3fallbackLoraConfigTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTff7b72?Tb4b4b4,
Te6edf3requirePrimaryTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ChannelReplacementPlan Tb4b4b4{
Tff7b72val Te6edf3normalizedSettings Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3settingsTb4b4b4, Te6edf3lora_config Tff7b72?: Te6edf3fallbackLoraConfigTb4b4b4)
Te6edf3requireTb4b4b4(Tff7b72!Te6edf3requirePrimary Tff7b72|Tff7b72| Te6edf3normalizedSettingsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Ta5d6ff"Ta5d6ffImported channel set must contain a primary channelTa5d6ff"
Tb4b4b4}
Te6edf3requireTb4b4b4(Te6edf3normalizedSettingsTb4b4b4.Te6edf3size Tff7b72<Tff7b72= Te6edf3CHANNEL_REPLACEMENT_SLOT_COUNTTb4b4b4) Tb4b4b4{
Ta5d6ff"Ta5d6ffImported channel set exceeds supported channel slot countTa5d6ff"
Tb4b4b4}
Tff7b72return Te6edf3ChannelReplacementPlanTb4b4b4(
Te6edf3normalizedSettings Tff7b72= Te6edf3normalizedSettingsTb4b4b4,
Te6edf3channelWrites Tff7b72=
Te6edf3getChannelReplacementListTb4b4b4(
Te6edf3new Tff7b72= Te6edf3normalizedSettingsTb4b4b4,
Te6edf3currentSettings Tff7b72= Te6edf3currentSettingsTb4b4b4,
Te6edf3minimumSlotCount Tff7b72= Te6edf3CHANNEL_REPLACEMENT_SLOT_COUNTTb4b4b4,
Te6edf3maximumSlotCount Tff7b72= Te6edf3CHANNEL_REPLACEMENT_SLOT_COUNTTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e/**
* Builds an authoritative [Channel] list for a full replacement. Every position in [new] is emitted, and any trailing
* positions beyond [new]'s range are emitted as disabled so the radio stops using them.
*
* Unlike a diff, this never skips settings already present in [currentSettings]. The imported set is authoritative, and
* stale local cache entries must not suppress a radio write.
*/
Tff7b72fun Td2a8ffgetChannelReplacementListTb4b4b4(
Te6edf3newTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72>Tb4b4b4,
Te6edf3currentSettingsTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72>Tb4b4b4,
Te6edf3minimumSlotCountTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3maximumSlotCountTb4b4b4: Tffa657Int Tff7b72= Tffa657IntTb4b4b4.Te6edf3MAX_VALUETb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelTff7b72> Tff7b72= Te6edf3buildList Tb4b4b4{
Te6edf3requireTb4b4b4(Te6edf3minimumSlotCount Tff7b72<Tff7b72= Te6edf3maximumSlotCountTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffminimumSlotCount must be <= maximumSlotCountTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3minimumLastIndex Tff7b72= Te6edf3minimumSlotCountTb4b4b4.Te6edf3coerceAtLeastTb4b4b4(T79c0ff0Tb4b4b4) Tff7b72- T79c0ff1
Tff7b72val Te6edf3maximumLastIndex Tff7b72= Te6edf3maximumSlotCountTb4b4b4.Te6edf3coerceAtLeastTb4b4b4(T79c0ff0Tb4b4b4) Tff7b72- T79c0ff1
Tff7b72val Te6edf3endIndex Tff7b72= Te6edf3maxOfTb4b4b4(Te6edf3currentSettingsTb4b4b4.Te6edf3lastIndexTb4b4b4, Te6edf3newTb4b4b4.Te6edf3lastIndexTb4b4b4, Te6edf3minimumLastIndexTb4b4b4)Tb4b4b4.Te6edf3coerceAtMostTb4b4b4(Te6edf3maximumLastIndexTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3endIndex Tff7b72< T79c0ff0Tb4b4b4) Tff7b72returnTf0883e@buildList
Tff7b72for Tb4b4b4(Te6edf3index Tff7b72in T79c0ff0.Tb4b4b4.Te6edf3endIndexTb4b4b4) Tb4b4b4{
Te6edf3addTb4b4b4(
Te6edf3ChannelTb4b4b4(
Te6edf3role Tff7b72=
Tff7b72when Tb4b4b4(Te6edf3indexTb4b4b4) Tb4b4b4{
T79c0ff0 Tff7b72-Tff7b72> Tff7b72if Tb4b4b4(Te6edf3newTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLED Tff7b72else Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARY
Tff7b72in T79c0ff1.Tb4b4b4.Te6edf3newTb4b4b4.Te6edf3lastIndex Tff7b72-Tff7b72> Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARY
Tff7b72else Tff7b72-Tff7b72> Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLED
Tb4b4b4}Tb4b4b4,
Te6edf3index Tff7b72= Te6edf3indexTb4b4b4,
Te6edf3settings Tff7b72= Te6edf3newTb4b4b4.Te6edf3getOrNullTb4b4b4(Te6edf3indexTb4b4b4) Tff7b72?: Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/**
* Normalizes replacement settings so firmware only materializes real, distinct channels.
*
* Slot zero is preserved as-is. Blank placeholder secondaries and semantic duplicates under [loraConfig] are removed,
* and the remaining secondaries compact into sequential slots.
*/
Tff7b72fun Td2a8ffnormalizeReplacementSettingsTb4b4b4(
Te6edf3settingsTb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72>Tb4b4b4,
Te6edf3loraConfigTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTff7b72?Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Te6edf3ChannelSettingsTff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3settingsTb4b4b4.Te6edf3size Tff7b72<Tff7b72= T79c0ff1Tb4b4b4) Tff7b72return Te6edf3settings
Tff7b72val Te6edf3effectiveLora Tff7b72= Te6edf3loraConfig Tff7b72?: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3primary Tff7b72= Te6edf3settingsTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3seen Tff7b72= Te6edf3mutableSetOfTff7b72<Te6edf3ChannelIdentityTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3primaryTb4b4b4.Te6edf3isChannelPlaceholderTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3seenTb4b4b4.Te6edf3addTb4b4b4(Te6edf3primaryTb4b4b4.Te6edf3channelIdentityTb4b4b4(Te6edf3effectiveLoraTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3compact Tff7b72= Te6edf3mutableListOfTb4b4b4(Te6edf3primaryTb4b4b4)
Tff7b72for Tb4b4b4(Te6edf3index Tff7b72in T79c0ff1.Tb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3lastIndexTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3candidate Tff7b72= Te6edf3settingsTff7b72[Te6edf3indexTff7b72]
Tff7b72val Te6edf3identity Tff7b72= Tff7b72if Tb4b4b4(Te6edf3candidateTb4b4b4.Te6edf3isChannelPlaceholderTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72null Tff7b72else Te6edf3candidateTb4b4b4.Te6edf3channelIdentityTb4b4b4(Te6edf3effectiveLoraTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3identity Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3seenTb4b4b4.Te6edf3addTb4b4b4(Te6edf3identityTb4b4b4)Tb4b4b4) Te6edf3compactTb4b4b4.Te6edf3addTb4b4b4(Te6edf3candidateTb4b4b4)
Tb4b4b4}
Tff7b72return Te6edf3compact
Tb4b4b4}

T8b949e/** True when these settings carry no name and no PSK, making them padding rather than an intended channel. */
Tff7b72fun Te6edf3ChannelSettingsTb4b4b4.Td2a8ffisChannelPlaceholderTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3nameTb4b4b4.Te6edf3isNullOrBlankTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3pskTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff0

T8b949e/** Semantic channel identity based on the effective name and effective PSK. */
Tff7b72data Tff7b72class T56d364ChannelIdentityTb4b4b4(Tff7b72val Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4, Tff7b72val Te6edf3pskTb4b4b4: Te6edf3ByteStringTb4b4b4) Tb4b4b4{
T8b949e// Never expose an effective PSK through diagnostics or an auto-generated data-class toString.
Tff7b72override Tff7b72fun Td2a8fftoStringTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657String Tff7b72= Ta5d6ff"Ta5d6ffChannelIdentity(name=Tffd700$Te6edf3nameTa5d6ff, psk=<redacted>)Ta5d6ff"
Tb4b4b4}

T8b949e/** Resolves this setting's semantic identity under [loraConfig]. */
Tff7b72fun Te6edf3ChannelSettingsTb4b4b4.Td2a8ffchannelIdentityTb4b4b4(Te6edf3loraConfigTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4)Tb4b4b4: Te6edf3ChannelIdentity Tb4b4b4{
Tff7b72val Te6edf3channel Tff7b72= Te6edf3ModelChannelTb4b4b4(Te6edf3settings Tff7b72= Tff7b72thisTb4b4b4, Te6edf3loraConfig Tff7b72= Te6edf3loraConfigTb4b4b4)
Tff7b72return Te6edf3ChannelIdentityTb4b4b4(Te6edf3name Tff7b72= Te6edf3channelTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3psk Tff7b72= Te6edf3channelTb4b4b4.Te6edf3pskTb4b4b4)
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.06s